package com.efun.framework.beetlsql;

import com.alibaba.druid.pool.DruidDataSource;
import org.beetl.sql.core.ClasspathLoader;
import org.beetl.sql.core.NameConversion;
import org.beetl.sql.core.UnderlinedNameConversion;
import org.beetl.sql.core.db.DBStyle;
import org.beetl.sql.core.db.MySqlStyle;
import org.beetl.sql.ext.spring4.BeetlSqlDataSource;
import org.beetl.sql.ext.spring4.SqlManagerFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.LinkedList;
import java.util.List;

/**
 * beetlsql的自动配置，这个配置有很多坑，一旦配置不正确，将会整个工程受累．
 * @author kinven on 17-7-29.
 */
@Configuration
@EnableConfigurationProperties({BeetlSqlProperties.class})
public class BeetlSqlAutoConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(BeetlSqlAutoConfiguration.class);

    public static final String SQL_MANAGER_FACTORY_BEAN_NAME = "sqlManagerFactoryBean";
    public static final String DAO_SUFFIX = "Dao"; //配置中的Daosuffix不会生效，先做此规定．

    private final BeetlSqlProperties beetlsqlProperties;

    public BeetlSqlAutoConfiguration(BeetlSqlProperties beetlsqlProperties){
        this.beetlsqlProperties = beetlsqlProperties;
    }

    @Bean
    public BeetlSqlDataSource getBeetlSqlDataSource(){
        BeetlSqlDataSource source = new BeetlSqlDataSource();
        BeetlSqlProperties.DataSourceSetting masteDatasourceSetting = beetlsqlProperties.getDruid().getMaste();
        BeetlSqlProperties.ConnectionSetting connectionSetting = beetlsqlProperties.getDruid().getConn();
        DruidDataSource masteDataSource = getDataSource(connectionSetting,masteDatasourceSetting);
        source.setMasterSource(masteDataSource);
        List<BeetlSqlProperties.DataSourceSetting> slaveDatasourceSettings = beetlsqlProperties.getDruid().getSlave();
        List<DruidDataSource> slaves = new LinkedList<DruidDataSource>();
        for(BeetlSqlProperties.DataSourceSetting slaveDatasourceSetting:slaveDatasourceSettings) {
            slaves.add(getDataSource(connectionSetting,slaveDatasourceSetting));
        }
        if(slaves.size() == 0){
            source.setSlaves(new DataSource[]{masteDataSource});
        } else {
            source.setSlaves(slaves.toArray(new DruidDataSource[slaves.size()]));
        }
        return source;
    }

    /**
     * 对主数据源进行事务控制
     * @param datasource
     * @return
     */
    @Bean
    @Primary
    public DataSourceTransactionManager getDataSourceTransactionManager(BeetlSqlDataSource datasource) {
        DataSourceTransactionManager dsm = new DataSourceTransactionManager();
        dsm.setDataSource(datasource.getMasterSource());
        return dsm;
    }

    /**
     * 根据公用配置和私有配置进行数据源的配置
     * @param connectionSetting
     * @param datasourceSetting
     * @return
     */
    private DruidDataSource getDataSource(BeetlSqlProperties.ConnectionSetting connectionSetting, BeetlSqlProperties.DataSourceSetting datasourceSetting){
        DruidDataSource druidDataSource = new DruidDataSource();
        if(connectionSetting.isEncrypt()){
            druidDataSource.setConnectProperties(connectionSetting.toProperties());
        }
        druidDataSource.setName(datasourceSetting.getName());
        druidDataSource.setDriverClassName(datasourceSetting.getDriverClassName());
        druidDataSource.setUrl(datasourceSetting.getUrl());
        druidDataSource.setUsername(datasourceSetting.getUsername());
        druidDataSource.setPassword(datasourceSetting.getPassword());
        druidDataSource.setMaxActive(datasourceSetting.getMaxActive());
        return druidDataSource;
    }

    @Bean(name=SQL_MANAGER_FACTORY_BEAN_NAME)
    @ConditionalOnBean({BeetlSqlBeanManager.class})
    public SqlManagerFactoryBean getSqlManagerFactoryBean(BeetlSqlDataSource beetlSqlDataSource,BeetlSqlBeanManager beetlSqlBeanManager){
        SqlManagerFactoryBean factory = new SqlManagerFactoryBean();
        factory.setCs(beetlSqlDataSource);
        factory.setDbStyle(beetlSqlBeanManager.getDbStyle());
        factory.setInterceptors(beetlSqlBeanManager.getInterceptors());
        factory.setNc(beetlSqlBeanManager().getNameConversion());
        factory.setSqlLoader(new ClasspathLoader(beetlsqlProperties.getSqlPath()));
        return factory;
    }

    @Bean
    public BeetlSqlBeanManager beetlSqlBeanManager(){
        BeetlSqlBeanManager beetlSqlBeanManager = new BeetlSqlBeanManager();
        beetlSqlBeanManager.setInterceptorsName(beetlsqlProperties.getInterceptors());
        beetlSqlBeanManager.setDbStyleName(beetlsqlProperties.getDbStyle());
        beetlSqlBeanManager.setNameConversionName(beetlsqlProperties.getNameConversion());
        beetlSqlBeanManager.setMasteDataSourceName(beetlsqlProperties.getDruid().getMaste().getName());
        beetlSqlBeanManager.setSlaveDataSourceNames(beetlsqlProperties.getDruid().getSlaveNames());
        return beetlSqlBeanManager;
    }

    @Bean
    public DBStyle mySqlStyle(){
        return new MySqlStyle();
    }

    @Bean
    public NameConversion underlinedNameConversion(){
        return new UnderlinedNameConversion();
    }
}
